summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGPUCode <geoster3d@gmail.com>2023-05-27 16:09:17 +0200
committerGPUCode <geoster3d@gmail.com>2023-06-18 11:45:18 +0200
commit7b2f680468bbac206f96b26a1300939be90f5f1b (patch)
treec8f506462c6d2b577ab0273e50c530fd7c71abbc
parentrenderer_vulkan: Use VMA for images (diff)
downloadyuzu-7b2f680468bbac206f96b26a1300939be90f5f1b.tar
yuzu-7b2f680468bbac206f96b26a1300939be90f5f1b.tar.gz
yuzu-7b2f680468bbac206f96b26a1300939be90f5f1b.tar.bz2
yuzu-7b2f680468bbac206f96b26a1300939be90f5f1b.tar.lz
yuzu-7b2f680468bbac206f96b26a1300939be90f5f1b.tar.xz
yuzu-7b2f680468bbac206f96b26a1300939be90f5f1b.tar.zst
yuzu-7b2f680468bbac206f96b26a1300939be90f5f1b.zip
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp9
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp6
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.h1
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp81
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_smaa.cpp12
-rw-r--r--src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp105
-rw-r--r--src/video_core/renderer_vulkan/vk_staging_buffer_pool.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp9
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h1
-rw-r--r--src/video_core/renderer_vulkan/vk_turbo_mode.cpp8
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp1
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.cpp107
-rw-r--r--src/video_core/vulkan_common/vulkan_memory_allocator.h12
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.cpp24
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.h91
16 files changed, 262 insertions, 211 deletions
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index e569523b6..ddf28ca28 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -233,8 +233,8 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
};
- const vk::Buffer dst_buffer = device.GetLogical().CreateBuffer(dst_buffer_info);
- MemoryCommit dst_buffer_memory = memory_allocator.Commit(dst_buffer, MemoryUsage::Download);
+ const vk::Buffer dst_buffer =
+ memory_allocator.CreateBuffer(dst_buffer_info, MemoryUsage::Download);
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([&](vk::CommandBuffer cmdbuf) {
@@ -308,8 +308,9 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
scheduler.Finish();
// Copy backing image data to the QImage screenshot buffer
- const auto dst_memory_map = dst_buffer_memory.Map();
- std::memcpy(renderer_settings.screenshot_bits, dst_memory_map.data(), dst_memory_map.size());
+ dst_buffer.Invalidate();
+ std::memcpy(renderer_settings.screenshot_bits, dst_buffer.Mapped().data(),
+ dst_buffer.Mapped().size());
renderer_settings.screenshot_complete_callback(false);
renderer_settings.screenshot_requested = false;
}
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index 82ca81c7e..ad3b29f0e 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -162,7 +162,7 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
SetUniformData(data, layout);
SetVertexData(data, framebuffer, layout);
- const std::span<u8> mapped_span = buffer_commit.Map();
+ const std::span<u8> mapped_span = buffer.Mapped();
std::memcpy(mapped_span.data(), &data, sizeof(data));
if (!use_accelerated) {
@@ -1074,7 +1074,6 @@ void BlitScreen::ReleaseRawImages() {
aa_image_view.reset();
aa_image.reset();
buffer.reset();
- buffer_commit = MemoryCommit{};
}
void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) {
@@ -1090,8 +1089,7 @@ void BlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer
.pQueueFamilyIndices = nullptr,
};
- buffer = device.GetLogical().CreateBuffer(ci);
- buffer_commit = memory_allocator.Commit(buffer, MemoryUsage::Upload);
+ buffer = memory_allocator.CreateBuffer(ci, MemoryUsage::Upload);
}
void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h
index 7fcfa9976..8365b5668 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.h
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.h
@@ -142,7 +142,6 @@ private:
vk::Sampler sampler;
vk::Buffer buffer;
- MemoryCommit buffer_commit;
std::vector<u64> resource_ticks;
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 8c33722d3..67356c679 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -50,7 +50,7 @@ size_t BytesPerIndex(VkIndexType index_type) {
}
}
-vk::Buffer CreateBuffer(const Device& device, u64 size) {
+vk::Buffer CreateBuffer(const Device& device, const MemoryAllocator& memory_allocator, u64 size) {
VkBufferUsageFlags flags =
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT |
@@ -60,7 +60,7 @@ vk::Buffer CreateBuffer(const Device& device, u64 size) {
if (device.IsExtTransformFeedbackSupported()) {
flags |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
}
- return device.GetLogical().CreateBuffer({
+ const VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -69,7 +69,8 @@ vk::Buffer CreateBuffer(const Device& device, u64 size) {
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
- });
+ };
+ return memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal);
}
} // Anonymous namespace
@@ -79,8 +80,8 @@ Buffer::Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams null_params)
Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_,
VAddr cpu_addr_, u64 size_bytes_)
: VideoCommon::BufferBase<VideoCore::RasterizerInterface>(rasterizer_, cpu_addr_, size_bytes_),
- device{&runtime.device}, buffer{CreateBuffer(*device, SizeBytes())},
- commit{runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal)} {
+ device{&runtime.device}, buffer{
+ CreateBuffer(*device, runtime.memory_allocator, SizeBytes())} {
if (runtime.device.HasDebuggingToolAttached()) {
buffer.SetObjectNameEXT(fmt::format("Buffer 0x{:x}", CpuAddr()).c_str());
}
@@ -138,7 +139,7 @@ public:
const u32 num_first_offset_copies = 4;
const size_t bytes_per_index = BytesPerIndex(index_type);
const size_t size_bytes = num_triangle_indices * bytes_per_index * num_first_offset_copies;
- buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{
+ const VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -147,14 +148,21 @@ public:
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
- });
+ };
+ buffer = memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal);
if (device.HasDebuggingToolAttached()) {
buffer.SetObjectNameEXT("Quad LUT");
}
- memory_commit = memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal);
- const StagingBufferRef staging = staging_pool.Request(size_bytes, MemoryUsage::Upload);
- u8* staging_data = staging.mapped_span.data();
+ const bool host_visible = buffer.IsHostVisible();
+ const StagingBufferRef staging = [&] {
+ if (host_visible) {
+ return StagingBufferRef{};
+ }
+ return staging_pool.Request(size_bytes, MemoryUsage::Upload);
+ }();
+
+ u8* staging_data = host_visible ? buffer.Mapped().data() : staging.mapped_span.data();
const size_t quad_size = bytes_per_index * 6;
for (u32 first = 0; first < num_first_offset_copies; ++first) {
@@ -164,29 +172,33 @@ public:
}
}
- scheduler.RequestOutsideRenderPassOperationContext();
- scheduler.Record([src_buffer = staging.buffer, src_offset = staging.offset,
- dst_buffer = *buffer, size_bytes](vk::CommandBuffer cmdbuf) {
- const VkBufferCopy copy{
- .srcOffset = src_offset,
- .dstOffset = 0,
- .size = size_bytes,
- };
- const VkBufferMemoryBarrier write_barrier{
- .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
- .pNext = nullptr,
- .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
- .dstAccessMask = VK_ACCESS_INDEX_READ_BIT,
- .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
- .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
- .buffer = dst_buffer,
- .offset = 0,
- .size = size_bytes,
- };
- cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy);
- cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
- VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, write_barrier);
- });
+ if (!host_visible) {
+ scheduler.RequestOutsideRenderPassOperationContext();
+ scheduler.Record([src_buffer = staging.buffer, src_offset = staging.offset,
+ dst_buffer = *buffer, size_bytes](vk::CommandBuffer cmdbuf) {
+ const VkBufferCopy copy{
+ .srcOffset = src_offset,
+ .dstOffset = 0,
+ .size = size_bytes,
+ };
+ const VkBufferMemoryBarrier write_barrier{
+ .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
+ .pNext = nullptr,
+ .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
+ .dstAccessMask = VK_ACCESS_INDEX_READ_BIT,
+ .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+ .buffer = dst_buffer,
+ .offset = 0,
+ .size = size_bytes,
+ };
+ cmdbuf.CopyBuffer(src_buffer, dst_buffer, copy);
+ cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, write_barrier);
+ });
+ } else {
+ buffer.Flush();
+ }
}
void BindBuffer(u32 first) {
@@ -587,11 +599,10 @@ void BufferCacheRuntime::ReserveNullBuffer() {
create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
}
create_info.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
- null_buffer = device.GetLogical().CreateBuffer(create_info);
+ null_buffer = memory_allocator.CreateBuffer(create_info, MemoryUsage::DeviceLocal);
if (device.HasDebuggingToolAttached()) {
null_buffer.SetObjectNameEXT("Null buffer");
}
- null_buffer_commit = memory_allocator.Commit(null_buffer, MemoryUsage::DeviceLocal);
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([buffer = *null_buffer](vk::CommandBuffer cmdbuf) {
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index cdeef8846..95446c732 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -48,7 +48,6 @@ private:
const Device* device{};
vk::Buffer buffer;
- MemoryCommit commit;
std::vector<BufferView> views;
};
@@ -142,7 +141,6 @@ private:
std::shared_ptr<QuadStripIndexBuffer> quad_strip_index_buffer;
vk::Buffer null_buffer;
- MemoryCommit null_buffer_commit;
std::unique_ptr<Uint8Pass> uint8_pass;
QuadIndexedPass quad_index_pass;
diff --git a/src/video_core/renderer_vulkan/vk_smaa.cpp b/src/video_core/renderer_vulkan/vk_smaa.cpp
index ff7c3a419..5efd7d66e 100644
--- a/src/video_core/renderer_vulkan/vk_smaa.cpp
+++ b/src/video_core/renderer_vulkan/vk_smaa.cpp
@@ -76,7 +76,7 @@ void TransitionImageLayout(vk::CommandBuffer& cmdbuf, VkImage image, VkImageLayo
void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& scheduler,
vk::Image& image, VkExtent2D dimensions, VkFormat format,
std::span<const u8> initial_contents = {}) {
- auto upload_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{
+ const VkBufferCreateInfo upload_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -85,9 +85,10 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
- });
- auto upload_commit = allocator.Commit(upload_buffer, MemoryUsage::Upload);
- std::ranges::copy(initial_contents, upload_commit.Map().begin());
+ };
+ auto upload_buffer = allocator.CreateBuffer(upload_ci, MemoryUsage::Upload);
+ std::ranges::copy(initial_contents, upload_buffer.Mapped().begin());
+ upload_buffer.Flush();
const std::array<VkBufferImageCopy, 1> regions{{{
.bufferOffset = 0,
@@ -111,9 +112,6 @@ void UploadImage(const Device& device, MemoryAllocator& allocator, Scheduler& sc
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
});
scheduler.Finish();
-
- // This should go out of scope before the commit
- auto upload_buffer2 = std::move(upload_buffer);
}
vk::ImageView CreateWrappedImageView(const Device& device, vk::Image& image, VkFormat format) {
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
index 74ca77216..62b251a9b 100644
--- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
@@ -30,55 +30,6 @@ constexpr VkDeviceSize MAX_STREAM_BUFFER_REQUEST_SIZE = 8_MiB;
constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128_MiB;
constexpr VkDeviceSize REGION_SIZE = STREAM_BUFFER_SIZE / StagingBufferPool::NUM_SYNCS;
-constexpr VkMemoryPropertyFlags HOST_FLAGS =
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
-constexpr VkMemoryPropertyFlags STREAM_FLAGS = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | HOST_FLAGS;
-
-bool IsStreamHeap(VkMemoryHeap heap) noexcept {
- return STREAM_BUFFER_SIZE < (heap.size * 2) / 3;
-}
-
-std::optional<u32> FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask,
- VkMemoryPropertyFlags flags) noexcept {
- for (u32 type_index = 0; type_index < props.memoryTypeCount; ++type_index) {
- if (((type_mask >> type_index) & 1) == 0) {
- // Memory type is incompatible
- continue;
- }
- const VkMemoryType& memory_type = props.memoryTypes[type_index];
- if ((memory_type.propertyFlags & flags) != flags) {
- // Memory type doesn't have the flags we want
- continue;
- }
- if (!IsStreamHeap(props.memoryHeaps[memory_type.heapIndex])) {
- // Memory heap is not suitable for streaming
- continue;
- }
- // Success!
- return type_index;
- }
- return std::nullopt;
-}
-
-u32 FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask,
- bool try_device_local) {
- std::optional<u32> type;
- if (try_device_local) {
- // Try to find a DEVICE_LOCAL_BIT type, Nvidia and AMD have a dedicated heap for this
- type = FindMemoryTypeIndex(props, type_mask, STREAM_FLAGS);
- if (type) {
- return *type;
- }
- }
- // Otherwise try without the DEVICE_LOCAL_BIT
- type = FindMemoryTypeIndex(props, type_mask, HOST_FLAGS);
- if (type) {
- return *type;
- }
- // This should never happen, and in case it does, signal it as an out of memory situation
- throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY);
-}
-
size_t Region(size_t iterator) noexcept {
return iterator / REGION_SIZE;
}
@@ -87,8 +38,7 @@ size_t Region(size_t iterator) noexcept {
StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_,
Scheduler& scheduler_)
: device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} {
- const vk::Device& dev = device.GetLogical();
- stream_buffer = dev.CreateBuffer(VkBufferCreateInfo{
+ const VkBufferCreateInfo stream_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -99,46 +49,13 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
- });
- if (device.HasDebuggingToolAttached()) {
- stream_buffer.SetObjectNameEXT("Stream Buffer");
- }
- VkMemoryDedicatedRequirements dedicated_reqs{
- .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS,
- .pNext = nullptr,
- .prefersDedicatedAllocation = VK_FALSE,
- .requiresDedicatedAllocation = VK_FALSE,
- };
- const auto requirements = dev.GetBufferMemoryRequirements(*stream_buffer, &dedicated_reqs);
- const bool make_dedicated = dedicated_reqs.prefersDedicatedAllocation == VK_TRUE ||
- dedicated_reqs.requiresDedicatedAllocation == VK_TRUE;
- const VkMemoryDedicatedAllocateInfo dedicated_info{
- .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
- .pNext = nullptr,
- .image = nullptr,
- .buffer = *stream_buffer,
};
- const auto memory_properties = device.GetPhysical().GetMemoryProperties().memoryProperties;
- VkMemoryAllocateInfo stream_memory_info{
- .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
- .pNext = make_dedicated ? &dedicated_info : nullptr,
- .allocationSize = requirements.size,
- .memoryTypeIndex =
- FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, true),
- };
- stream_memory = dev.TryAllocateMemory(stream_memory_info);
- if (!stream_memory) {
- LOG_INFO(Render_Vulkan, "Dynamic memory allocation failed, trying with system memory");
- stream_memory_info.memoryTypeIndex =
- FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, false);
- stream_memory = dev.AllocateMemory(stream_memory_info);
- }
-
+ stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream);
if (device.HasDebuggingToolAttached()) {
- stream_memory.SetObjectNameEXT("Stream Buffer Memory");
+ stream_buffer.SetObjectNameEXT("Stream Buffer");
}
- stream_buffer.BindMemory(*stream_memory, 0);
- stream_pointer = stream_memory.Map(0, STREAM_BUFFER_SIZE);
+ stream_pointer = stream_buffer.Mapped();
+ ASSERT_MSG(!stream_pointer.empty(), "Stream buffer must be host visible!");
}
StagingBufferPool::~StagingBufferPool() = default;
@@ -199,7 +116,7 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
return StagingBufferRef{
.buffer = *stream_buffer,
.offset = static_cast<VkDeviceSize>(offset),
- .mapped_span = std::span<u8>(stream_pointer + offset, size),
+ .mapped_span = stream_pointer.subspan(offset, size),
.usage{},
.log2_level{},
.index{},
@@ -247,7 +164,7 @@ std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t s
StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage,
bool deferred) {
const u32 log2 = Common::Log2Ceil64(size);
- vk::Buffer buffer = device.GetLogical().CreateBuffer({
+ const VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -259,17 +176,15 @@ StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
- });
+ };
+ vk::Buffer buffer = memory_allocator.CreateBuffer(buffer_ci, usage);
if (device.HasDebuggingToolAttached()) {
++buffer_index;
buffer.SetObjectNameEXT(fmt::format("Staging Buffer {}", buffer_index).c_str());
}
- MemoryCommit commit = memory_allocator.Commit(buffer, usage);
- const std::span<u8> mapped_span = IsHostVisible(usage) ? commit.Map() : std::span<u8>{};
-
+ const std::span<u8> mapped_span = buffer.Mapped();
StagingBuffer& entry = GetCache(usage)[log2].entries.emplace_back(StagingBuffer{
.buffer = std::move(buffer),
- .commit = std::move(commit),
.mapped_span = mapped_span,
.usage = usage,
.log2_level = log2,
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
index 4fd15f11a..5f69f08b1 100644
--- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
@@ -46,7 +46,6 @@ private:
struct StagingBuffer {
vk::Buffer buffer;
- MemoryCommit commit;
std::span<u8> mapped_span;
MemoryUsage usage;
u32 log2_level;
@@ -97,8 +96,7 @@ private:
Scheduler& scheduler;
vk::Buffer stream_buffer;
- vk::DeviceMemory stream_memory;
- u8* stream_pointer = nullptr;
+ std::span<u8> stream_pointer;
size_t iterator = 0;
size_t used_iterator = 0;
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 10defe6cb..28985b6fe 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -839,14 +839,14 @@ bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) {
VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL);
- if (buffer_commits[level]) {
+ if (buffers[level]) {
return *buffers[level];
}
const auto new_size = Common::NextPow2(needed_size);
static constexpr VkBufferUsageFlags flags =
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
- buffers[level] = device.GetLogical().CreateBuffer({
+ const VkBufferCreateInfo temp_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -855,9 +855,8 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
- });
- buffer_commits[level] = std::make_unique<MemoryCommit>(
- memory_allocator.Commit(buffers[level], MemoryUsage::DeviceLocal));
+ };
+ buffers[level] = memory_allocator.CreateBuffer(temp_ci, MemoryUsage::DeviceLocal);
return *buffers[level];
}
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 9481f2531..220943116 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -116,7 +116,6 @@ public:
static constexpr size_t indexing_slots = 8 * sizeof(size_t);
std::array<vk::Buffer, indexing_slots> buffers{};
- std::array<std::unique_ptr<MemoryCommit>, indexing_slots> buffer_commits{};
};
class Image : public VideoCommon::ImageBase {
diff --git a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp
index 6417d7e31..460d8d59d 100644
--- a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp
+++ b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp
@@ -41,7 +41,7 @@ void TurboMode::Run(std::stop_token stop_token) {
auto& dld = m_device.GetLogical();
// Allocate buffer. 2MiB should be sufficient.
- auto buffer = dld.CreateBuffer(VkBufferCreateInfo{
+ const VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -50,10 +50,8 @@ void TurboMode::Run(std::stop_token stop_token) {
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
- });
-
- // Commit some device local memory for the buffer.
- auto commit = m_allocator.Commit(buffer, MemoryUsage::DeviceLocal);
+ };
+ vk::Buffer buffer = m_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal);
// Create the descriptor pool to contain our descriptor.
static constexpr VkDescriptorPoolSize pool_size{
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 631d5e378..541f0c1da 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -603,6 +603,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
};
const VmaAllocatorCreateInfo allocator_info = {
+ .flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT,
.physicalDevice = physical,
.device = *logical,
.pVulkanFunctions = &functions,
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
index 7f860cccd..d2e1ef58e 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp
@@ -51,11 +51,59 @@ struct Range {
case MemoryUsage::Download:
return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
+ case MemoryUsage::Stream:
+ return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
+ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
}
ASSERT_MSG(false, "Invalid memory usage={}", usage);
return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
}
+[[nodiscard]] VkMemoryPropertyFlags MemoryUsageRequiredVmaFlags(MemoryUsage usage) {
+ switch (usage) {
+ case MemoryUsage::DeviceLocal:
+ return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+ case MemoryUsage::Upload:
+ case MemoryUsage::Stream:
+ return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
+ case MemoryUsage::Download:
+ return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
+ }
+ ASSERT_MSG(false, "Invalid memory usage={}", usage);
+ return {};
+}
+
+[[nodiscard]] VkMemoryPropertyFlags MemoryUsagePreferedVmaFlags(MemoryUsage usage) {
+ return usage != MemoryUsage::DeviceLocal ? VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
+ : VkMemoryPropertyFlags{};
+}
+
+[[nodiscard]] VmaAllocationCreateFlags MemoryUsageVmaFlags(MemoryUsage usage) {
+ switch (usage) {
+ case MemoryUsage::Upload:
+ case MemoryUsage::Stream:
+ return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
+ case MemoryUsage::Download:
+ return VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
+ case MemoryUsage::DeviceLocal:
+ return VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
+ VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT;
+ }
+ return {};
+}
+
+[[nodiscard]] VmaMemoryUsage MemoryUsageVma(MemoryUsage usage) {
+ switch (usage) {
+ case MemoryUsage::DeviceLocal:
+ case MemoryUsage::Stream:
+ return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
+ case MemoryUsage::Upload:
+ case MemoryUsage::Download:
+ return VMA_MEMORY_USAGE_AUTO_PREFER_HOST;
+ }
+ return VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
+}
+
} // Anonymous namespace
class MemoryAllocation {
@@ -178,17 +226,18 @@ void MemoryCommit::Release() {
}
MemoryAllocator::MemoryAllocator(const Device& device_)
- : device{device_}, properties{device_.GetPhysical().GetMemoryProperties().memoryProperties},
+ : device{device_}, allocator{device.GetAllocator()},
+ properties{device_.GetPhysical().GetMemoryProperties().memoryProperties},
buffer_image_granularity{
device_.GetPhysical().GetProperties().limits.bufferImageGranularity} {}
MemoryAllocator::~MemoryAllocator() = default;
vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const {
- const VmaAllocationCreateInfo alloc_info = {
+ const VmaAllocationCreateInfo alloc_ci = {
.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT,
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
- .requiredFlags = 0,
+ .requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
.preferredFlags = 0,
.pool = VK_NULL_HANDLE,
.pUserData = nullptr,
@@ -196,12 +245,40 @@ vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const {
VkImage handle{};
VmaAllocation allocation{};
- vk::Check(
- vmaCreateImage(device.GetAllocator(), &ci, &alloc_info, &handle, &allocation, nullptr));
- return vk::Image(handle, *device.GetLogical(), device.GetAllocator(), allocation,
+
+ vk::Check(vmaCreateImage(allocator, &ci, &alloc_ci, &handle, &allocation, nullptr));
+
+ return vk::Image(handle, *device.GetLogical(), allocator, allocation,
device.GetDispatchLoader());
}
+vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const {
+ const VmaAllocationCreateInfo alloc_ci = {
+ .flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT |
+ MemoryUsageVmaFlags(usage),
+ .usage = MemoryUsageVma(usage),
+ .requiredFlags = MemoryUsageRequiredVmaFlags(usage),
+ .preferredFlags = MemoryUsagePreferedVmaFlags(usage),
+ .pool = VK_NULL_HANDLE,
+ .pUserData = nullptr,
+ };
+
+ VkBuffer handle{};
+ VmaAllocationInfo alloc_info{};
+ VmaAllocation allocation{};
+ VkMemoryPropertyFlags property_flags{};
+
+ vk::Check(vmaCreateBuffer(allocator, &ci, &alloc_ci, &handle, &allocation, &alloc_info));
+ vmaGetAllocationMemoryProperties(allocator, allocation, &property_flags);
+
+ u8* data = reinterpret_cast<u8*>(alloc_info.pMappedData);
+ const std::span<u8> mapped_data = data ? std::span<u8>{data, ci.size} : std::span<u8>{};
+ const bool is_coherent = property_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+
+ return vk::Buffer(handle, *device.GetLogical(), allocator, allocation, mapped_data, is_coherent,
+ device.GetDispatchLoader());
+}
+
MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) {
// Find the fastest memory flags we can afford with the current requirements
const u32 type_mask = requirements.memoryTypeBits;
@@ -221,12 +298,6 @@ MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, M
return TryCommit(requirements, flags).value();
}
-MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage) {
- auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), usage);
- buffer.BindMemory(commit.Memory(), commit.Offset());
- return commit;
-}
-
bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) {
const u32 type = FindType(flags, type_mask).value();
vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({
@@ -302,16 +373,4 @@ std::optional<u32> MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 ty
return std::nullopt;
}
-bool IsHostVisible(MemoryUsage usage) noexcept {
- switch (usage) {
- case MemoryUsage::DeviceLocal:
- return false;
- case MemoryUsage::Upload:
- case MemoryUsage::Download:
- return true;
- }
- ASSERT_MSG(false, "Invalid memory usage={}", usage);
- return false;
-}
-
} // namespace Vulkan
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h
index f9ee53cfb..f449bc8d0 100644
--- a/src/video_core/vulkan_common/vulkan_memory_allocator.h
+++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h
@@ -9,6 +9,8 @@
#include "common/common_types.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
+VK_DEFINE_HANDLE(VmaAllocator)
+
namespace Vulkan {
class Device;
@@ -17,9 +19,11 @@ class MemoryAllocation;
/// Hints and requirements for the backing memory type of a commit
enum class MemoryUsage {
- DeviceLocal, ///< Hints device local usages, fastest memory type to read and write from the GPU
+ DeviceLocal, ///< Requests device local host visible buffer, falling back to device local
+ ///< memory.
Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads
Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks
+ Stream, ///< Requests device local host visible buffer, falling back host memory.
};
/// Ownership handle of a memory commitment.
@@ -82,6 +86,8 @@ public:
vk::Image CreateImage(const VkImageCreateInfo& ci) const;
+ vk::Buffer CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsage usage) const;
+
/**
* Commits a memory with the specified requirements.
*
@@ -113,13 +119,11 @@ private:
std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const;
const Device& device; ///< Device handle.
+ VmaAllocator allocator; ///< Vma allocator.
const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties.
std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations.
VkDeviceSize buffer_image_granularity; // The granularity for adjacent offsets between buffers
// and optimal images
};
-/// Returns true when a memory usage is guaranteed to be host visible.
-bool IsHostVisible(MemoryUsage usage) noexcept;
-
} // namespace Vulkan
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp
index 5d088dc58..c01a9478e 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.cpp
+++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp
@@ -561,14 +561,28 @@ void Image::Release() const noexcept {
}
}
-void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const {
- Check(dld->vkBindBufferMemory(owner, handle, memory, offset));
+void Buffer::Flush() const {
+ if (!is_coherent) {
+ vmaFlushAllocation(allocator, allocation, 0, VK_WHOLE_SIZE);
+ }
+}
+
+void Buffer::Invalidate() const {
+ if (!is_coherent) {
+ vmaInvalidateAllocation(allocator, allocation, 0, VK_WHOLE_SIZE);
+ }
}
void Buffer::SetObjectNameEXT(const char* name) const {
SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name);
}
+void Buffer::Release() const noexcept {
+ if (handle) {
+ vmaDestroyBuffer(allocator, handle, allocation);
+ }
+}
+
void BufferView::SetObjectNameEXT(const char* name) const {
SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name);
}
@@ -707,12 +721,6 @@ Queue Device::GetQueue(u32 family_index) const noexcept {
return Queue(queue, *dld);
}
-Buffer Device::CreateBuffer(const VkBufferCreateInfo& ci) const {
- VkBuffer object;
- Check(dld->vkCreateBuffer(handle, &ci, nullptr, &object));
- return Buffer(object, handle, *dld);
-}
-
BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const {
VkBufferView object;
Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object));
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h
index 8ec708774..44fce47a5 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.h
+++ b/src/video_core/vulkan_common/vulkan_wrapper.h
@@ -673,6 +673,84 @@ private:
const DeviceDispatch* dld = nullptr;
};
+class Buffer {
+public:
+ explicit Buffer(VkBuffer handle_, VkDevice owner_, VmaAllocator allocator_,
+ VmaAllocation allocation_, std::span<u8> mapped_, bool is_coherent_,
+ const DeviceDispatch& dld_) noexcept
+ : handle{handle_}, owner{owner_}, allocator{allocator_},
+ allocation{allocation_}, mapped{mapped_}, is_coherent{is_coherent_}, dld{&dld_} {}
+ Buffer() = default;
+
+ Buffer(const Buffer&) = delete;
+ Buffer& operator=(const Buffer&) = delete;
+
+ Buffer(Buffer&& rhs) noexcept
+ : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, allocator{rhs.allocator},
+ allocation{rhs.allocation}, mapped{rhs.mapped},
+ is_coherent{rhs.is_coherent}, dld{rhs.dld} {}
+
+ Buffer& operator=(Buffer&& rhs) noexcept {
+ Release();
+ handle = std::exchange(rhs.handle, nullptr);
+ owner = rhs.owner;
+ allocator = rhs.allocator;
+ allocation = rhs.allocation;
+ mapped = rhs.mapped;
+ is_coherent = rhs.is_coherent;
+ dld = rhs.dld;
+ return *this;
+ }
+
+ ~Buffer() noexcept {
+ Release();
+ }
+
+ VkBuffer operator*() const noexcept {
+ return handle;
+ }
+
+ void reset() noexcept {
+ Release();
+ handle = nullptr;
+ }
+
+ explicit operator bool() const noexcept {
+ return handle != nullptr;
+ }
+
+ /// Returns the host mapped memory, an empty span otherwise.
+ std::span<u8> Mapped() noexcept {
+ return mapped;
+ }
+
+ std::span<const u8> Mapped() const noexcept {
+ return mapped;
+ }
+
+ /// Returns true if the buffer is mapped to the host.
+ bool IsHostVisible() const noexcept {
+ return !mapped.empty();
+ }
+
+ void Flush() const;
+
+ void Invalidate() const;
+
+ void SetObjectNameEXT(const char* name) const;
+
+private:
+ void Release() const noexcept;
+
+ VkBuffer handle = nullptr;
+ VkDevice owner = nullptr;
+ VmaAllocator allocator = nullptr;
+ VmaAllocation allocation = nullptr;
+ std::span<u8> mapped = {};
+ bool is_coherent = false;
+ const DeviceDispatch* dld = nullptr;
+};
+
class Queue {
public:
/// Construct an empty queue handle.
@@ -696,17 +774,6 @@ private:
const DeviceDispatch* dld = nullptr;
};
-class Buffer : public Handle<VkBuffer, VkDevice, DeviceDispatch> {
- using Handle<VkBuffer, VkDevice, DeviceDispatch>::Handle;
-
-public:
- /// Attaches a memory allocation.
- void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
-
- /// Set object name.
- void SetObjectNameEXT(const char* name) const;
-};
-
class BufferView : public Handle<VkBufferView, VkDevice, DeviceDispatch> {
using Handle<VkBufferView, VkDevice, DeviceDispatch>::Handle;
@@ -886,8 +953,6 @@ public:
Queue GetQueue(u32 family_index) const noexcept;
- Buffer CreateBuffer(const VkBufferCreateInfo& ci) const;
-
BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const;
ImageView CreateImageView(const VkImageViewCreateInfo& ci) const;